<template>
  <view class="image-cropper" style="background-color: rgba(0,0,0,0.8);" @touchstart.stop="cutTouchStart" @touchmove.stop="cutTouchMove" @touchend.stop="cutTouchEnd">
    <!-- 背景图片层 -->
    <view class="main-image" :style="{width: imageWidth + 'px', height: imageHeight + 'px', transform: 'translate(' + imageLeft + 'px,' + imageTop + 'px) scale(' + scale + ',' + scale + ') rotateZ(' + angle + 'deg)'}">
      <image :src="src" mode="widthFix" :style="{width: '100%', height: '100%'}"></image>
    </view>
    <!-- 裁剪框层 -->
    <view class="cropper-box" :style="{width: cropperWidth + 'px', height: cropperHeight + 'px', left: cropperLeft + 'px', top: cropperTop + 'px'}">
      <!-- 裁剪框 -->
      <view class="cropper-box-mask">
        <view class="cropper-box-border">
          <!-- 四角 -->
          <view class="corner left-top"></view>
          <view class="corner right-top"></view>
          <view class="corner left-bottom"></view>
          <view class="corner right-bottom"></view>
          <!-- 边线 -->
          <view class="border border-top"></view>
          <view class="border border-right"></view>
          <view class="border border-bottom"></view>
          <view class="border border-left"></view>
          <!-- 九宫格 -->
          <view class="grid-line grid-line-h-1"></view>
          <view class="grid-line grid-line-h-2"></view>
          <view class="grid-line grid-line-v-1"></view>
          <view class="grid-line grid-line-v-2"></view>
        </view>
      </view>
    </view>
  </view>
</template>

<script>
  export default {
    name: 'image-cropper',
    props: {
      src: {
        type: String,
        default: ''
      },
      aspectRatio: { // 裁剪框宽高比
        type: Number,
        default: 1
      },
      outputQuality: { // 输出图片质量
        type: Number,
        default: 0.9
      },
      outputFileType: { // 输出图片格式
        type: String,
        default: 'jpg'
      },
      minBoxWidth: { // 最小裁剪框宽度
        type: Number,
        default: 100
      },
      minBoxHeight: { // 最小裁剪框高度
        type: Number,
        default: 100
      }
    },
    data() {
      return {
        // 图片相关
        imageWidth: 0,        // 图片宽度
        imageHeight: 0,       // 图片高度
        imageLeft: 0,         // 图片左边距
        imageTop: 0,          // 图片上边距
        scale: 1,             // 图片缩放比例
        angle: 0,             // 图片旋转角度
        
        // 裁剪框相关
        cropperWidth: 0,      // 裁剪框宽度
        cropperHeight: 0,     // 裁剪框高度
        cropperLeft: 0,       // 裁剪框左边距
        cropperTop: 0,        // 裁剪框上边距
        
        // 触摸相关
        startX: 0,            // 触摸起始点X
        startY: 0,            // 触摸起始点Y
        moveX: 0,             // X轴移动距离
        moveY: 0,             // Y轴移动距离
        startL: 0,            // 触摸起始点左边距
        startT: 0,            // 触摸起始点上边距
        startW: 0,            // 触摸起始宽度
        startH: 0,            // 触摸起始高度
        startScale: 1,        // 触摸起始缩放比例
        mode: 'move',         // 操作模式
        
        // 系统信息
        windowWidth: 0,       // 窗口宽度
        windowHeight: 0,      // 窗口高度
        pixelRatio: 1,        // 设备像素比
        
        // 是否已初始化
        isInitialized: false,
        
        // 裁剪数据
        data: {}
      }
    },
    watch: {
      src() {
        // 图片链接变化时重新加载
        this.init();
      }
    },
    mounted() {
      // 获取系统信息
      uni.getSystemInfo({
        success: (res) => {
          this.windowWidth = res.windowWidth;
          this.windowHeight = res.windowHeight;
          this.pixelRatio = res.pixelRatio;
          
          // 初始化
          if (this.src) {
            this.init();
          }
        }
      });
    },
    methods: {
      // 初始化
      init() {
        if (this.src === '') return;
        
        // 获取图片信息
        uni.getImageInfo({
          src: this.src,
          success: (res) => {
            // 计算图片宽高比
            const ratio = res.width / res.height;
            
            // 计算图片的合适尺寸
            let imageWidth = this.windowWidth;
            let imageHeight = imageWidth / ratio;
            
            // 如果图片高度超出屏幕，则按高度适应
            if (imageHeight > this.windowHeight) {
              imageHeight = this.windowHeight * 0.8;
              imageWidth = imageHeight * ratio;
            }
            
            // 设置图片尺寸和位置
            this.imageWidth = imageWidth;
            this.imageHeight = imageHeight;
            this.imageLeft = (this.windowWidth - imageWidth) / 2;
            this.imageTop = (this.windowHeight - imageHeight) / 2;
            
            // 计算裁剪框尺寸和位置
            this.calculateCropperBox();
            
            // 标记已初始化
            this.isInitialized = true;
            
            // 更新数据
            this.updateData();
            
            // 触发组件就绪事件
            this.$emit('ready', {
              width: this.imageWidth,
              height: this.imageHeight,
              left: this.imageLeft,
              top: this.imageTop
            });
          },
          fail: (err) => {
            console.error('获取图片信息失败', err);
            uni.showToast({
              title: '图片加载失败',
              icon: 'none'
            });
          }
        });
      },
      
      // 计算裁剪框尺寸和位置
      calculateCropperBox() {
        // 根据宽高比计算裁剪框尺寸
        let cropperWidth = this.windowWidth * 0.7;
        let cropperHeight = cropperWidth / this.aspectRatio;
        
        // 确保裁剪框不超过图片
        if (cropperWidth > this.imageWidth) {
          cropperWidth = this.imageWidth;
          cropperHeight = cropperWidth / this.aspectRatio;
        }
        
        if (cropperHeight > this.imageHeight) {
          cropperHeight = this.imageHeight;
          cropperWidth = cropperHeight * this.aspectRatio;
        }
        
        // 确保裁剪框不小于最小尺寸
        if (cropperWidth < this.minBoxWidth) {
          cropperWidth = this.minBoxWidth;
          cropperHeight = cropperWidth / this.aspectRatio;
        }
        
        if (cropperHeight < this.minBoxHeight) {
          cropperHeight = this.minBoxHeight;
          cropperWidth = cropperHeight * this.aspectRatio;
        }
        
        // 设置裁剪框尺寸和位置
        this.cropperWidth = cropperWidth;
        this.cropperHeight = cropperHeight;
        this.cropperLeft = (this.windowWidth - cropperWidth) / 2;
        this.cropperTop = (this.windowHeight - cropperHeight) / 2;
      },
      
      // 触摸开始
      cutTouchStart(e) {
        if (!this.isInitialized) return;
        
        const touch = e.touches[0];
        this.startX = touch.clientX;
        this.startY = touch.clientY;
        this.startL = this.imageLeft;
        this.startT = this.imageTop;
        this.startW = this.imageWidth;
        this.startH = this.imageHeight;
        this.startScale = this.scale;
        
        // 判断操作模式
        if (e.touches.length === 1) {
          this.mode = 'move';
        } else if (e.touches.length === 2) {
          this.mode = 'scale';
          // 计算两点之间的距离
          const xMove = e.touches[1].clientX - e.touches[0].clientX;
          const yMove = e.touches[1].clientY - e.touches[0].clientY;
          this.startDistance = Math.sqrt(xMove * xMove + yMove * yMove);
        }
      },
      
      // 触摸移动
      cutTouchMove(e) {
        if (!this.isInitialized) return;
        
        const touch = e.touches[0];
        
        if (this.mode === 'move') {
          // 单指移动图片
          this.moveX = touch.clientX - this.startX;
          this.moveY = touch.clientY - this.startY;
          this.imageLeft = this.startL + this.moveX;
          this.imageTop = this.startT + this.moveY;
        } else if (this.mode === 'scale' && e.touches.length === 2) {
          // 双指缩放图片
          const xMove = e.touches[1].clientX - e.touches[0].clientX;
          const yMove = e.touches[1].clientY - e.touches[0].clientY;
          const distance = Math.sqrt(xMove * xMove + yMove * yMove);
          
          const scaleChange = distance / this.startDistance;
          this.scale = this.startScale * scaleChange;
          
          // 限制缩放比例
          if (this.scale < 0.5) this.scale = 0.5;
          if (this.scale > 3) this.scale = 3;
        }
        
        // 更新数据
        this.updateData();
      },
      
      // 触摸结束
      cutTouchEnd() {
        if (!this.isInitialized) return;
        this.mode = 'move';
      },
      
      // 更新裁剪数据
      updateData() {
        this.data = {
          imageWidth: this.imageWidth,
          imageHeight: this.imageHeight,
          imageLeft: this.imageLeft,
          imageTop: this.imageTop,
          scale: this.scale,
          angle: this.angle,
          cropperWidth: this.cropperWidth,
          cropperHeight: this.cropperHeight,
          cropperLeft: this.cropperLeft,
          cropperTop: this.cropperTop
        };
        
        // 触发绘制前事件
        this.$emit('beforeDraw', this.data);
      },
      
      // 设置旋转角度
      setAngle(angle) {
        this.angle = angle;
        this.updateData();
      },
      
      // 获取裁剪图片
      getCropperImage(callback) {
        if (!this.isInitialized) {
          callback && callback('');
          return;
        }
        
        // 创建画布上下文
        const ctx = uni.createCanvasContext('cropper-canvas', this);
        
        // 计算裁剪区域在原图上的位置和大小
        const cropBoxLeft = this.cropperLeft - this.imageLeft;
        const cropBoxTop = this.cropperTop - this.imageTop;
        const scaleWidth = this.imageWidth * this.scale;
        const scaleHeight = this.imageHeight * this.scale;
        
        // 设置背景色
        ctx.setFillStyle('#ffffff');
        ctx.fillRect(0, 0, this.cropperWidth, this.cropperHeight);
        
        // 保存状态
        ctx.save();
        
        // 裁剪区域
        ctx.beginPath();
        ctx.rect(0, 0, this.cropperWidth, this.cropperHeight);
        ctx.clip();
        
        // 绘制图片
        ctx.translate(this.cropperWidth / 2, this.cropperHeight / 2);
        ctx.rotate((this.angle * Math.PI) / 180);
        ctx.translate(-this.cropperWidth / 2, -this.cropperHeight / 2);
        ctx.drawImage(
          this.src,
          cropBoxLeft / this.scale,
          cropBoxTop / this.scale,
          this.cropperWidth / this.scale,
          this.cropperHeight / this.scale,
          0,
          0,
          this.cropperWidth,
          this.cropperHeight
        );
        
        // 恢复状态
        ctx.restore();
        
        // 绘制完成后导出图片
        ctx.draw(false, () => {
          // 导出图片
          uni.canvasToTempFilePath({
            canvasId: 'cropper-canvas',
            quality: this.outputQuality,
            fileType: this.outputFileType,
            success: (res) => {
              callback && callback(res.tempFilePath);
            },
            fail: (err) => {
              console.error('导出图片失败', err);
              callback && callback('');
            }
          }, this);
        });
      },
      
      // 查找组件
      selectComponent(selector) {
        return this;
      }
    }
  }
</script>

<style>
  .image-cropper {
    width: 100%;
    height: 100%;
    position: fixed;
    top: 0;
    left: 0;
    z-index: 10;
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    overflow: hidden;
  }
  
  .main-image {
    position: absolute;
    z-index: 11;
    top: 0;
    left: 0;
    background-color: #000;
  }
  
  .cropper-box {
    position: absolute;
    z-index: 12;
    box-sizing: border-box;
    border: 1px solid rgba(255, 255, 255, 0.3);
  }
  
  .cropper-box-mask {
    position: relative;
    width: 100%;
    height: 100%;
    background-color: transparent;
  }
  
  .cropper-box-border {
    position: relative;
    width: 100%;
    height: 100%;
    background-color: transparent;
  }
  
  .corner {
    position: absolute;
    z-index: 13;
    width: 20px;
    height: 20px;
    border: 2px solid #fff;
    border-radius: 2px;
  }
  
  .left-top {
    left: -2px;
    top: -2px;
    border-right: none;
    border-bottom: none;
  }
  
  .right-top {
    right: -2px;
    top: -2px;
    border-left: none;
    border-bottom: none;
  }
  
  .left-bottom {
    left: -2px;
    bottom: -2px;
    border-right: none;
    border-top: none;
  }
  
  .right-bottom {
    right: -2px;
    bottom: -2px;
    border-left: none;
    border-top: none;
  }
  
  .border {
    position: absolute;
    border: 1px dashed rgba(255, 255, 255, 0.5);
    width: 100%;
    height: 100%;
    box-sizing: border-box;
  }
  
  .grid-line {
    position: absolute;
    background-color: rgba(255, 255, 255, 0.3);
  }
  
  .grid-line-h-1 {
    width: 100%;
    height: 1px;
    top: 33.3%;
  }
  
  .grid-line-h-2 {
    width: 100%;
    height: 1px;
    top: 66.6%;
  }
  
  .grid-line-v-1 {
    width: 1px;
    height: 100%;
    left: 33.3%;
  }
  
  .grid-line-v-2 {
    width: 1px;
    height: 100%;
    left: 66.6%;
  }
</style> 